package com.temp.controller.user;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.temp.dto.UpdateUserInfoDTO;
import com.temp.dto.UserForgetPWDTO;
import com.temp.dto.UserLoginDTO;
import com.temp.dto.UserRegisterDTO;
import com.temp.entity.User;
import com.temp.enumeration.RoleType;
import com.temp.exception.BaseException;
import com.temp.result.Result;
import com.temp.service.RouteService;
import com.temp.service.UserService;
import com.temp.utils.EpusdtSignUtil;
import com.temp.utils.PasswordHelper;
import com.temp.utils.ShiroUtils;
import com.temp.vo.RouteVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/api/user")
@Api(tags = "用户相关接口")
@Slf4j
@Validated
public class UserController {

    @Autowired
    private UserService userService;

    @Autowired
    private RouteService routeService;

    @Value("${signature.key:Aa199214012@.0}")
    private String signature;

    @PostMapping("/login")
    @ApiOperation("用户登录")
    public Result login(@Valid @RequestBody UserLoginDTO userLoginDTO) {
        log.info("用户登录，登录信息:{}", userLoginDTO);
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(userLoginDTO.getEmail(), userLoginDTO.getPassword());
        try {
            subject.login(token);
            return Result.success("apiMsg.loginSuccess");
        } catch (AuthenticationException e) {
            return Result.error("apiMsg.emailOrPwError");
        }
    }

    @PostMapping("/register")
    @ApiOperation("用户注册")
    public Result register(@Valid @RequestBody UserRegisterDTO userRegisterDTO) {
        log.info("用户注册，注册信息:{}", userRegisterDTO);
        if(!userRegisterDTO.getPassword().equals(userRegisterDTO.getAgainPassword())) {
            throw new BaseException("apiMsg.notEqualPw");
        }
        User user = new User();
        BeanUtils.copyProperties(userRegisterDTO, user);
        // 生成随机盐值
        String salt = PasswordHelper.generateSalt();
        user.setSalt(salt);
        // 加密密码
        user.setPasswordHash(PasswordHelper.encryptPassword(userRegisterDTO.getPassword(), salt));
        boolean isSuccess = userService.saveUser(user, RoleType.USER.getValue());
        if(isSuccess) {
            Map<String, Object> stringObjectMap = buildRegisterParams(user);
            String key = EpusdtSignUtil.generateSign(stringObjectMap, signature);
            return  Result.success(key, "apiMsg.optionSuccess");
        } else {
            return Result.error("apiMsg.optionError");
        }
    }

    @GetMapping("/info")
    @ApiOperation("用户信息")
    @RequiresPermissions("user:user:info")
    public Result userinfo() {
        User user = ShiroUtils.getUser();
        log.info("当前用户的信息:{}", user);
        User one = userService.getOne(Wrappers.<User>lambdaQuery().eq(User::getId, user.getId()));
        return one == null ? Result.success(null,"apiMsg.querySuccess") : Result.success(one,"apiMsg.queryError");
    }

    @GetMapping("/routes")
    @ApiOperation("路由信息")
    @RequiresPermissions("user:user:routes")
    public Result userRoute() {
        User user = ShiroUtils.getUser();
        log.info("当前用户的信息:{}", user);
        List<RouteVO> routes = routeService.findAuthorizedRoutesByUserId(user.getId());
        return Result.success(routes,"apiMsg.querySuccess");
    }

    @PostMapping("/forgetPW")
    @ApiOperation("重置用户密码")
    public Result forgetPassword(@Valid @RequestBody UserForgetPWDTO userForgetPWDTO) {
        log.info("用户重置密码", userForgetPWDTO);
        if(!userForgetPWDTO.getNewPassword().equals(userForgetPWDTO.getAgainPassword())) {
            throw new BaseException("apiMsg.notEqualPw");
        }
        User user = userService.getOne(Wrappers.<User>lambdaQuery()
                .eq(User::getUsername, userForgetPWDTO.getUsername())
                .eq(User::getEmail, userForgetPWDTO.getEmail()));
        if(user == null) {
            throw new BaseException("apiMsg.notExistUser");
        }
        Map<String, Object> stringObjectMap = buildRegisterParams(user);
        stringObjectMap.put("Signature", userForgetPWDTO.getSignature());
        boolean verifySign = EpusdtSignUtil.verifySign((JSONObject) stringObjectMap, signature);
        if(!verifySign) {
            throw new BaseException("apiMsg.signError");
        }
        // 生成随机盐值
        String salt = PasswordHelper.generateSalt();
        user.setSalt(salt);
        // 加密密码
        user.setPasswordHash(PasswordHelper.encryptPassword(userForgetPWDTO.getNewPassword(), salt));
        boolean isSuccess = userService.updateById(user);

        return isSuccess ? Result.success("apiMsg.optionSuccess") : Result.error("apiMsg.optionError");
    }

    @PostMapping("/update")
    @ApiOperation("更新用户信息")
    @RequiresPermissions("user:user:update")
    public Result updateInfo(@Valid @RequestBody UpdateUserInfoDTO userInfoDTO) {
        log.info("用户更新的信息:{}", userInfoDTO);
        User user = ShiroUtils.getUser();
        BeanUtils.copyProperties(userInfoDTO, user);
        return userService.saveOrUpdate(user)
                ? Result.success("apiMsg.optionSuccess")
                : Result.error("optionError");
    }

    @GetMapping("/logout")
    @ApiOperation("用户登出")
    @RequiresPermissions("user:user:logout")
    public Result logout() {
        ShiroUtils.logout();
        return Result.success("apiMsg.logoutSuccess");
    }

    private Map<String, Object> buildRegisterParams(User user) {
        Map<String, Object> params = new HashMap<>();
        params.put("EMAIL",user.getEmail());
        params.put("ID", user.getId());
        return params;
    }
}
